package com.cmq.web_1.uploadfile;

import java.io.*;
import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
import jakarta.servlet.http.*;
import java.util.UUID;

@WebServlet("/upload")
@MultipartConfig(
        maxFileSize = 1024 * 1024 * 10,      // 单个文件最大10MB
        maxRequestSize = 1024 * 1024 * 50,   // 总请求最大50MB
        fileSizeThreshold = 1024 * 1024      // 内存缓存大小1MB
)
public class FileUploadServlet extends HttpServlet {

    // 允许上传的文件类型
    private static final String[] ALLOWED_TYPES = {
            "image/jpeg", "image/png", "image/gif",
            "application/pdf", "text/plain",
            "application/msword",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.ms-excel",
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    };

    // 上传文件存储目录
    private String uploadPath;

    @Override
    public void init() throws ServletException {
        // 初始化上传目录
        uploadPath = getServletContext().getRealPath("/") + "uploads";
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            boolean created = uploadDir.mkdirs();
            if (created) {
                System.out.println("上传目录创建成功: " + uploadPath);
            } else {
                System.err.println("上传目录创建失败: " + uploadPath);
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();

        try {
            StringBuilder resultMessage = new StringBuilder();
            int successCount = 0;
            int failCount = 0;

            // 获取所有上传的文件
            for (Part part : request.getParts()) {
                String fileName = getFileName(part);

                if (fileName != null && !fileName.trim().isEmpty()) {
                    String uploadResult = processSingleFile(part);
                    if (uploadResult.startsWith("成功")) {
                        successCount++;
                    } else {
                        failCount++;
                    }
                    resultMessage.append(uploadResult).append("<br>");
                }
            }

            // 设置结果消息
            String message = String.format("上传完成！成功：%d个，失败：%d个", successCount, failCount);
            request.getSession().setAttribute("message", message);
            request.getSession().setAttribute("detailMessage", resultMessage.toString());

            // 重定向到结果页面
            response.sendRedirect("upload-result.jsp");

        } catch (Exception e) {
            out.println("<script>alert('上传失败：" + e.getMessage() + "'); history.back();</script>");
            e.printStackTrace();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String action = request.getParameter("action");

        if ("download".equals(action)) {
            // 处理文件下载
            downloadFile(request, response);
        } else if ("list".equals(action)) {
            // 显示文件列表
            listFiles(request, response);
        } else if ("delete".equals(action)) {
            // 删除文件
            deleteFile(request, response);
        } else {
            // 显示上传表单
            showUploadForm(request, response);
        }
    }

    /**
     * 获取上传文件的原始文件名
     */
    private String getFileName(Part part) {
        String contentDisposition = part.getHeader("content-disposition");
        String[] tokens = contentDisposition.split(";");
        for (String token : tokens) {
            if (token.trim().startsWith("filename")) {
                return token.substring(token.indexOf("=") + 2, token.length() - 1);
            }
        }
        return null;
    }

    /**
     * 处理单个文件上传
     */
    private String processSingleFile(Part part) throws IOException {
        String originalFileName = getFileName(part);
        String contentType = part.getContentType();
        long fileSize = part.getSize();

        // 校验文件是否为空
        if (fileSize == 0) {
            return "文件 '" + originalFileName + "' 为空文件，跳过上传";
        }

        // 校验文件类型
        if (!isAllowedType(contentType)) {
            return "文件 '" + originalFileName + "' 类型不支持: " + contentType;
        }

        // 校验文件大小
        if (fileSize > 10 * 1024 * 1024) {
            return "文件 '" + originalFileName + "' 大小超过10MB限制";
        }

        // 生成UUID文件名
        String fileExtension = getFileExtension(originalFileName);
        String uuidFileName = UUID.randomUUID().toString() + fileExtension;
        String filePath = uploadPath + File.separator + uuidFileName;

        // 保存文件
        try (InputStream input = part.getInputStream();
             FileOutputStream output = new FileOutputStream(filePath)) {

            byte[] buffer = new byte[1024];
            int length;
            while ((length = input.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
        }

        // 记录文件信息（在实际系统中可以保存到数据库）
        logFileInfo(originalFileName, uuidFileName, fileSize, contentType);

        return String.format("成功：文件 '%s' → '%s' (%d bytes)",
                originalFileName, uuidFileName, fileSize);
    }

    /**
     * 校验文件类型是否允许
     */
    private boolean isAllowedType(String contentType) {
        if (contentType == null) {
            return false;
        }

        for (String allowedType : ALLOWED_TYPES) {
            if (allowedType.equals(contentType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf(".");
        return (lastDotIndex > 0) ? fileName.substring(lastDotIndex) : "";
    }

    /**
     * 记录文件信息（可扩展为数据库存储）
     */
    private void logFileInfo(String originalName, String uuidName, long size, String type) {
        System.out.println("文件上传记录: " +
                "原文件名='" + originalName + "', " +
                "存储名='" + uuidName + "', " +
                "大小=" + size + " bytes, " +
                "类型=" + type);
    }

    /**
     * 处理文件下载
     */
    private void downloadFile(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        String fileName = request.getParameter("file");
        if (fileName == null || fileName.isEmpty()) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "文件名参数缺失");
            return;
        }

        // 安全校验：防止路径遍历攻击
        if (fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "非法文件名");
            return;
        }

        File file = new File(uploadPath + File.separator + fileName);
        if (!file.exists()) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在: " + fileName);
            return;
        }

        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition",
                "attachment; filename=\"" + fileName + "\"");
        response.setContentLengthLong(file.length());

        // 传输文件
        try (FileInputStream inputStream = new FileInputStream(file);
             OutputStream outputStream = response.getOutputStream()) {

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }
    }

    /**
     * 删除文件
     */
    private void deleteFile(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        String fileName = request.getParameter("file");
        if (fileName == null || fileName.isEmpty()) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "文件名参数缺失");
            return;
        }

        // 安全校验
        if (fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "非法文件名");
            return;
        }

        File file = new File(uploadPath + File.separator + fileName);
        if (file.exists() && file.delete()) {
            request.getSession().setAttribute("message", "文件删除成功: " + fileName);
        } else {
            request.getSession().setAttribute("message", "文件删除失败: " + fileName);
        }

        response.sendRedirect("upload?action=list");
    }

    /**
     * 显示文件列表
     */
    private void listFiles(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        File uploadDir = new File(uploadPath);
        File[] files = uploadDir.listFiles();

        request.setAttribute("fileList", files != null ? files : new File[0]);
        request.getRequestDispatcher("/file-list.jsp").forward(request, response);
    }

    /**
     * 显示上传表单
     */
    private void showUploadForm(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        request.getRequestDispatcher("/upload-form.jsp").forward(request, response);
    }
}